<template>
  <div :id="uuid" :key="uuid" :class="{ w100: withSelect }">
    <div
      v-if="withSelect"
      class="tagTreeFormItem"
      :style="{ maxHeight: inputMaxHeight }"
      @click="openDialog()"
    >
      <div class="tagWrap">
        <el-tag
          size="small"
          :closable="!item.noClose"
          v-for="(item, index) in tagShowList"
          :key="index"
          @close="handleCloseTag(item, true)"
        >
          <span class="tagTest">
            {{ tagFormatter(item) }}
          </span>
        </el-tag>
      </div>
      <el-icon class="rightIcon"><ArrowRight /></el-icon>
    </div>
    <op-dialog
      ref="TreeDialogRef"
      destroy-on-close
      :title="title"
      @open="handleOpen"
      @close="handleClose"
      class="treeDialog"
      append-to-body
      @confirm="handleConfirm"
      size="big"
      height="auto"
    >
      <div v-loading.lock="loading">
        <slot name="prepend" :config="{ ...attrs, prependSlot: prependSlot }"></slot>
        <el-row :gutter="0">
          <el-col :span="10">
            <div class="innerTreeWrap">
              <div class="mb10" v-if="showRadio">
                <el-radio-group v-model="radio" @change="handleRadioChange">
                  <el-radio label="All">All</el-radio>
                  <el-radio label="Designated">Designated</el-radio>
                </el-radio-group>
              </div>
              <op-tree
                withFilter
                filterPlaceholder="Search or Select"
                class="innerTreeBox"
                :data="treeList"
                :props="defaultProps"
                ref="TreeRef"
                :node-key="nodeKey"
                show-checkbox
                @check="handleCheck"
              />
            </div>
          </el-col>
          <el-col :span="14">
            <div class="innerTagWrap">
              <div class="innerTagTitle">
                <span>Selected {{ tagList.length }}</span>
              </div>
              <div class="innerTagBox">
                <el-tag
                  closable
                  v-for="(item, index) in tagList"
                  :key="index"
                  @close="handleCloseTag(item)"
                >
                  {{ tagFormatter(item) }}
                </el-tag>
              </div>
              <el-icon
                v-show="tagList && tagList.length > 1"
                @click.stop="clearAll"
                class="rightIcon"
              >
                <CircleClose />
              </el-icon>
            </div>
          </el-col>
        </el-row>
      </div>
      <slot name="append" :config="{ ...attrs, prependSlot: prependSlot }" />
    </op-dialog>
  </div>
</template>

<script setup>
import { ElMessage } from 'element-plus';
import { apiMethods } from '@/utils/http';
import { computed } from 'vue';

const idGen = () => new Date().getTime();
const attrs = useAttrs();

const emit = defineEmits(['update:modelValue', 'itemEvent', 'destroy']);

const {
  url,
  apiMethod,
  params,
  singleCheck,
  modelValue,
  prop,
  // defaultID,
  withSelect,
  tier,
  valueKey,
  nodeKey,
  selectType,
  defaultProps,
  withFatherNode,
  dataRecallList,
  isNode,
  isEmpty,
  ...props
} = defineProps({
  url: {
    type: String,
    default: '/department/getCompanyDeptStaffList',
  },
  apiMethod: {
    type: String,
    default: 'post',
  },
  // 接口参数
  params: {
    type: Object,
    default: () => {},
  },
  // 是否为单选
  singleCheck: {
    type: Boolean,
    default: false,
  },
  // // 若需要展示默认ID，请传入
  // defaultID: {
  //   type: Array,
  //   default: () => [],
  // },
  title: {
    type: String,
    default: 'Add Staff',
  },
  prop: {
    type: String,
    default: '',
  },
  modelValue: {
    type: Array,
    default: () => [],
  },
  withSelect: {
    type: Boolean,
    default: true,
  },
  // 若接口需处理层级或选择对象，请传入
  tier: {
    type: String,
    default: 'data.data',
  },
  // 每个树节点用来作为唯一标识的属性，整棵树应该是唯一的
  nodeKey: {
    type: String,
    default: 'id',
  },
  valueKey: {
    type: String,
    default: '',
  },
  // 若仅可选择人，请忽视，type=1，部门，type=2，项目，type=3,选择到人,type=4 new
  selectType: {
    type: String,
    default: '4',
  },
  // 配置选项
  defaultProps: {
    type: Object,
    default: () => ({
      label: 'name', // 显示名称
    }),
  },
  // 是否需要传入父节点给taglist展示给后端(每层全选都会将父节点传入)
  withFatherNode: {
    type: Boolean,
    default: false,
  },
  // 是否展示选择框，控制全选和全不选
  showRadio: {
    type: Boolean,
    default: false,
  },
  prependSlot: {
    // prepend 插槽名
    type: String,
    default: '',
  },
  appendSlot: {
    // append 插槽名
    type: String,
    default: '',
  },
  dataRecallList: {
    type: Array,
  },
  tagFormatter: {
    type: Function,
    default: item => item.name,
  },
  isNode: {
    // 原defaultID，数值结构是否为Node
    type: Boolean,
    default: false,
  },
  callApiEachOpen: {
    // 每次打开对话框重新根据参数请求接口
    type: Boolean,
    default: false,
  },
  checkedByApi: {
    // 根据接口的selected字段进行勾选
    type: Boolean,
    default: false,
  },
  isEmpty: {
    // confirm确认的时候，是否可以为空
    type: Boolean,
    default: false,
  },
  collapseTags: {
    // 最多展示多少个
    type: Number,
    default: 0,
  },
  inputMaxHeight: {
    // 手动设置formItem的高度
    type: String,
    default: '150px',
  },
});
const TreeRef = ref();
const TreeDialogRef = ref();

const uuid = ref(idGen());
const radio = ref('Designated');

const tagList = ref([]);
const selectorTagList = ref([]);
const treeList = ref([]);
const flattenTreeList = ref([]);
// const treeDialogVisible = ref(false);
const loading = ref(false);

const tagShowList = computed(() => {
  if (!props.collapseTags || selectorTagList.value?.length <= props.collapseTags) {
    return selectorTagList.value;
  } else {
    let diff = selectorTagList.value?.length - props.collapseTags;
    let arr = selectorTagList.value.slice(0, props.collapseTags);
    arr.push({
      name: '+' + diff,
      noClose: true,
    });
    return arr;
  }
});

onMounted(() => {
  if (withSelect) initData();
});

function openDialog(cb) {
  nextTick(() => {
    TreeDialogRef.value.init();
    if (!treeList.value.length || props.callApiEachOpen) {
      initData(cb);
    } else {
      cb && cb({ treeList: treeList.value, flattenTreeList: flattenTreeList.value });
    }
  });
}

function closeDialog() {
  TreeDialogRef.value.destroy();
}

function initData(cb) {
  getTreeList(cb);
}

async function getTreeList(cb) {
  loading.value = true;
  let res = await apiMethods[apiMethod](url, params);
  let code = res.data.code || res.data.errorCode;
  if (code === '200') {
    const tierArr = tier.split('.');
    let arr = res;
    tierArr.forEach(i => {
      arr = arr[i];
    });
    arr = removeEmptyChildren(arr);
    treeList.value = [...arr];

    flattenTreeList.value = flatten(treeList.value);

    if (props.checkedByApi) {
      let ids = [];
      flattenTreeList.value.forEach(item => {
        if (item.selected === true) {
          ids.push(item[nodeKey]);
          tagList.value.push(item);
        }
      });
      // console.log(flattenTreeList.value);
      // console.log('check id', ids);
      setTreeCheck(ids);
    }

    if (checkDuplicate(flattenTreeList.value, nodeKey)) {
      clearAll();
      closeDialog();
      return console.error('Data has duplicate nodeKey');
    }

    // if (defaultID && defaultID.length > 0) setTaglist();
    if (modelValue && modelValue.length > 0) setTaglist();

    if (!withSelect) handleOpen();
    loading.value = false;
    cb && cb({ treeList: treeList.value, flattenTreeList: flattenTreeList.value });
  } else {
    loading.value = false;
  }
}

function flatten(arr) {
  return arr
    .map(item => [item, ...(Array.isArray(item.children) ? flatten(item.children) : [])])
    .flat(Infinity);
}
// function flatten(arr) {
//   return arr.reduce((result, item) => {
//     return [...result, item, ...(Array.isArray(item.children) ? flatten(item.children) : [])];
//   }, []);
// }

// 若有重复nodeKey，则返回true
function checkDuplicate(arr, nodeKey) {
  // let ids = [];
  // arr.forEach(i => {
  //   ids.push(i[nodeKey]);
  // });
  // console.log(ids);

  let set = new Set();
  for (let item of arr) {
    let value = item[nodeKey];
    if (set.has(value)) {
      return true;
    }
    set.add(value);
  }
  return false;
}

function // 树形结构中删除空children
removeEmptyChildren(node) {
  if (!node || !node?.length) return [];
  node.forEach(item => {
    if ('children' in item && !item.children) {
      delete item.children;
    }
    if (item.children && item.children.length === 0) {
      delete item.children;
    } else if (item.children && item.children.length > 0) {
      removeEmptyChildren(item.children);
    }
  });
  return node;
}

function setTaglist() {
  // if (prop) {
  tagList.value = [];
  modelValue.forEach(item => {
    const key = valueKey || nodeKey;
    const value = isNode ? item[key] : item;
    flattenTreeList.value.forEach(i => {
      if (value === i[key]) {
        tagList.value.push(i);
      }
    });
  });
  selectorTagList.value = [...tagList.value];
  // }
  // else {
  //   defaultID.forEach(item => {
  //     flattenTreeList.value.forEach(i => {
  //       if (item === i.id) {
  //         tagList.value = [];
  //         tagList.value.push(i);
  //       }
  //     });
  //   });
  // }
}

function handleConfirm() {
  if (tagList.value.length === 0 && !isEmpty) {
    return ElMessage.warning(`Please select at least one piece of data`);
  }
  selectorTagList.value = tagList.value;
  const value = isNode
    ? selectorTagList.value
    : selectorTagList.value.map(i => (valueKey ? i[valueKey] : i[nodeKey]));
  emit('update:modelValue', value);
  emit('itemEvent', {
    value,
    eventName: 'confirm',
    prop,
    treeList: treeList.value,
    flattenTreeList: flattenTreeList.value,
    selectorTagList: selectorTagList.value,
  });
  if (withSelect) {
    closeDialog();
  }
}

// function buttonClick(prop) {
//   if (prop === 'cancel') {
//     clearAll();
//     closeDialog();
//   }
//   if (prop === 'confirm') {
//     if (tagList.value.length === 0)
//       return ElMessage.warning(`Please select at least one piece of data`);
//     selectorTagList.value = tagList.value;

//     emit('selectConfirmed', selectorTagList.value);
//     closeDialog();
//   }
// }

function clearAll() {
  TreeRef.value && TreeRef.value.clearFilterText();
  radio.value = 'Designated';
  tagList.value = [];
  emit('itemEvent', { value: tagList.value, eventName: 'clear', prop });
  // 对话框子组件时，若未首次打开不存在于DOM
  if (TreeRef.value) {
    setTreeCheck([]);
  }
}

function handleOpen() {
  if (withSelect) {
    tagList.value = selectorTagList.value;
    let arr = [];
    tagList.value.forEach(item => arr.push(item[nodeKey]));
    emit('itemEvent', { value: tagList.value });
    setTreeCheck(arr);
  }

  // 回显
  if (dataRecallList) {
    treeDataRecall(dataRecallList);
  }
}

// 打开时回显数据
function treeDataRecall(idList) {
  if (!idList.length) return;
  let arr = [];
  let nodeArr = [];
  let num = 0;
  let key = valueKey || nodeKey;
  flattenTreeList.value.forEach((item, index) => {
    if (!item.children) num++;
    idList?.forEach((i, ind) => {
      if (item[key] === i) {
        arr.push(item[key]);
        nodeArr.push(item);
      }
    });
  });
  setTreeCheck(arr);
  handleCheck(arr, nodeArr);
  if (tagList.value.length === num) radio.value = 'All';
}

function multipleTag(checkedNodes) {
  // 树形选择框 反选All radio
  // if (!checkedNodes?.length) return;
  radio.value = checkedNodes?.length === flattenTreeList.value.length ? 'All' : 'Designated';
  tagList.value = [];
  checkedNodes?.forEach(item => {
    if (withFatherNode || !item.children) {
      if (item.type == selectType || ['4'].includes(selectType)) tagList.value.push(item);
    }
  });
  emit('itemEvent', { value: tagList.value, prop });
}

function singleTag(data, checkedNodes) {
  tagList.value = [];
  setTreeCheck([]);
  if (checkedNodes.length > 0) {
    if (withFatherNode || !data.children) {
      if (data.type == selectType || ['4'].includes(selectType)) {
        tagList.value.push(data);
        setTreeCheck([data?.[nodeKey]]);
      }
    }
  }
  emit('itemEvent', { value: tagList.value, prop });
}

function handleClose() {
  clearAll();
  closeDialog();
  emit('destroy');
}

// function // 数据中uesrid不唯一
// setId(list) {
//   list.forEach(item => {
//     item.realId = item.id + '&' + item.parent;
//     if (item.children?.length) {
//       setId(item.children);
//     }
//   });
// }

// function findId(list, arr1, arr2) {
//   list.forEach(item => {
//     if (arr1.find(a => a === item.realId)) {
//       arr2.push(item.realId);
//     } else {
//       arr1.push(item.realId);
//     }
//     if (item.children?.length) {
//       findId(item.children, arr1, arr2);
//     }
//   });
// }

function handleCloseTag(tag, closeConfirmTag) {
  let arr = [];
  // 从formItem input框中直接删除tag
  if (closeConfirmTag) {
    selectorTagList.value = selectorTagList.value.filter(item => item[nodeKey] != tag[nodeKey]);
    selectorTagList.value.forEach(item => arr.push(item[nodeKey]));
    let valueFlag = isNode ? selectorTagList.value : selectorTagList.value.map(i => i[nodeKey]);
    emit('itemEvent', { value: valueFlag, prop, eventName: 'change' });
    // console.log('closeConfirmTag');
  } else {
    tagList.value = tagList.value.filter(item => item[nodeKey] != tag[nodeKey]);
    tagList.value.forEach(item => arr.push(item[nodeKey]));
    let valueFlag = isNode ? tagList.value : tagList.value.map(i => i[nodeKey]);
    emit('itemEvent', { value: valueFlag, prop, eventName: 'change' });
    setTreeCheck(arr);
  }
  radio.value = 'Designated';
}

function handleRadioChange(val) {
  if (val === 'All') {
    // 选中所有非禁用节点
    let ids = [];
    let nodes = [];
    flattenTreeList.value.forEach(i => {
      if (i?.disabled === false) {
        ids.push(i?.[nodeKey]);
        nodes.push(i);
      }
    });
    setTreeCheck(ids);
    handleCheck([], { checkedNodes: nodes });
  } else {
    // 取消选中所有节点
    clearAll();
  }
}

function // 树选中checkBox
handleCheck(data, { checkedNodes }) {
  if (singleCheck) {
    singleTag(data, checkedNodes);
  } else {
    multipleTag(checkedNodes);
  }
}

function // 设置目前选中的节点，使用此方法必须设置 node-key 属性
setTreeCheck(val) {
  nextTick(() => {
    TreeRef.value.ref.setCheckedKeys(val);
    // setCheckedKeys
    // (keys, leafOnly) 接收两个参数:
    // 1. 一个需要被选中的多节点 key 的数组
    // 2. 布尔类型的值 如果设置为 true，将只设置选中的叶子节点状态。 默认值是 false.
  });
}

function setValue() {
  TreeRef.value && TreeRef.value.clearFilterText();

  if (modelValue && modelValue.length > 0 && treeList.value.length > 0) {
    setTaglist();
  } else {
    tagList.value = [];
    selectorTagList.value = [];
    if (TreeRef.value) setTreeCheck([]);
  }
}

watch(
  () => modelValue,
  val => {
    setValue();
  },
  {
    immediate: true,
    deep: true,
  }
);

// watch(
//   () => defaultID,
//   () => setValue()
// );

defineExpose({
  openDialog,
  closeDialog,
  treeDataRecall,
});
</script>

<style scoped lang="scss">
.tagTreeFormItem {
  position: relative;
  min-height: 30px;
  max-height: 150px;
  line-height: 26px;
  width: 100%;
  // padding: 0 4px;
  display: flex;
  justify-content: space-between;
  background-color: #fff;
  border: solid 1px rgb(220, 223, 230);
  border-radius: 4px;
  cursor: text;
  overflow: auto;
  .el-tag {
    margin: 0 2px;
  }
  .el-icon-circle-close {
    margin: 10px 10px 0 0;
    &:hover {
      color: var(--el-color-primary);
      cursor: pointer;
    }
  }
  .tagWrap {
    padding-right: 15px;
  }
}
.rightIcon {
  position: absolute;
  right: 10px;
  top: 50%;
  margin-top: -7px;
  cursor: pointer;
  &:hover {
    color: var(--el-color-primary);
  }
}

.treeDialog {
  .innerTreeWrap {
    border: 1px solid rgb(220, 223, 230);
    border-right: 0;
    height: 46vh;
    padding: 10px;
    display: flex;
    flex-direction: column;

    .innerTreeAll {
    }

    :deep(.innerTreeBox) {
      flex: 1;
      overflow-y: auto;
    }
  }
  .innerTagWrap {
    position: relative;
    height: 46vh;
    border: solid 1px rgb(220, 223, 230);
    padding: 10px;
    padding-right: 0;
    .innerTagTitle {
      height: 30px;
      display: flex;
      align-items: center;
    }
    .innerTagBox {
      height: calc(100% - 40px);
      padding-right: 15px;
      overflow: auto;
      .el-tag {
        margin: 0 6px 6px 0;
      }
    }
    .el-icon-circle-close {
      position: absolute;
      right: 35px;
      top: 20px;
      &:hover {
        color: var(--el-color-primary);
        cursor: pointer;
      }
    }
  }
}

.treeTag {
  height: 40px;
  display: flex;
  justify-content: left;
  align-items: center;
  background: #f9fafb;
  border-radius: 4px;
  border: 1px solid #e5e6ec;
  padding: 10px;
  box-sizing: border-box;
  color: #606266;
  margin-top: 10px;
  :deep().el-tag__content {
    display: flex;
    align-items: center;
  }
}

.w100 {
  width: 100%;
}
</style>
